package net.boyandi.picback;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.joda.time.LocalDateTime;

import at.fhj.utils.misc.ProgressTracker;
import at.fhj.utils.swing.JMsgPane;
import at.fhj.utils.swing.ProgressWorker;

class FolderScanner extends ProgressWorker {
    
    private static Logger logger = Logger.getLogger(FolderScanner.class.getName());

    private final PicBack app;
    private final List<FolderScanResult> results;

    public FolderScanner(PicBack app, ProgressTracker tracker) {
        super(tracker);
        this.app = app;
        this.results = new ArrayList<FolderScanResult>();
    }

    @Override
    public Object construct() {
        try {
            startScanning(getProgressTracker());
        } catch (final Throwable th) {
            JMsgPane.showErrorDialog(app, th);
            logger.error("Scanning failed", th);
        }
        return null;
    }
    
    public List<FolderScanResult> getResults() {
        return results;
    }

    private void startScanning(ProgressTracker tracker) throws IOException {
        logger.info("Scanning started");
        tracker.startTask("Scanning folders", 1.0);
        List<String> folders = app.getSettings().getFoldersToScan();
        tracker.setTaskIncUnit(1.0 / folders.size());
        for (String folder : folders) {
            File f = new File(folder);
            recurse(f.getCanonicalPath(), f);
            tracker.incTaskProgress();
            if (getProgressTracker().isCancelled()) {
                break;
            }
        }
        if (getProgressTracker().isCancelled()) {
            logger.info("Scanning cancelled");
        } else {
            logger.info("Scanning finished");
            tracker.processFinished();
            app.setFolderScanResults(results);
        }
    }

    private void recurse(String startFolder, File folder) throws IOException {
        if (getProgressTracker().isCancelled()) {
            return;
        }
        String albumName = folder.getName();
        int numStarred = 0, numNonStarred = 0;
        long sizeStarred = 0, sizeNonStarred = 0;
        PicasaIniParser parser = null;
        
        final boolean isManaged;
        String path = folder.getAbsolutePath();
        if (PicasaIniParser.isManagedByPicasa(path)) {
            parser = new PicasaIniParser(path);
            parser.parse();
            
            albumName = parser.getAlbumName();
            numStarred = parser.getNumStarred();
            isManaged = true;
        } else {
            logger.warn("Folder '" + path + "' is not managed by Picasa. Nothing will be removed");
            isManaged = false;
        }
        
        long minLastMod = folder.lastModified();
        for (File file : folder.listFiles(app.getFilesToBackupFilter())) {
            if (parser != null  &&  parser.isStarred(file.getName())) {
                sizeStarred += file.length();
            } else {
                sizeNonStarred += file.length();
                numNonStarred++;
            }
            if (file.lastModified() < minLastMod) {
                minLastMod = file.lastModified();
            }
        }
        
        String fullPath = folder.getCanonicalPath();
        if (!fullPath.startsWith(startFolder)) {
            throw new IOException(fullPath + " is not within " + startFolder);
        }
        String relativePath = fullPath.substring(startFolder.length());
        if (relativePath.startsWith(File.separator)) {
            relativePath = relativePath.substring(1);
        }
        results.add(
            new FolderScanResult(
                albumName,
                numStarred,  sizeStarred, 
                numNonStarred, sizeNonStarred,
                startFolder,
                relativePath,
                new LocalDateTime(minLastMod),
                isManaged
            )
        );
        if (getProgressTracker().isCancelled()) {
            return;
        }
        for (File subFolder : folder.listFiles(DIRECTORY_FILTER)) {
            recurse(startFolder, subFolder);
        }
    }
    
    private static final FileFilter DIRECTORY_FILTER = new FileFilter() {
        public boolean accept(File file) {
            return file.isDirectory();
        } 
    };

}